package com.heima.wemedia.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.api.feign.ApArticleFeignClient;
import com.heima.audit.DFA.SensitiveWordFilter;
import com.heima.audit.baidu.BaiduImageScan;
import com.heima.audit.baidu.BaiduTextScan;
import com.heima.audit.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.service.WmNewsAutoAuditService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;

/**
 * @Descriptioin WmNewsAutoAuditServiceImpl
 * @Author AvA
 * @Date 2024-11-26
 */
@Service
@Transactional
public class WmNewsAutoAuditServiceImpl implements WmNewsAutoAuditService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private BaiduTextScan baiduTextScan;

    @Autowired
    private BaiduImageScan baiduImageScan;

    @Autowired
    private Tess4jClient tess4jClient;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private ApArticleFeignClient apArticleFeignClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 自媒体端文章审核
     *
     * @param id 文章Id
     */
    @Override
    @Transactional
    public void AutoAuditNews(Integer id) {
        WmNews wmNews = wmNewsMapper.selectById(id);

        if (ObjectUtil.isEmpty(wmNews)) {
            throw new RuntimeException("文章不存在");
        }

        //如果文章状态为 提交(待审核) 获取全部文字和图片
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            Map<String, Object> textAndImages = ExtractTextAndImages(wmNews);
            String text = (String) textAndImages.get("Text");
            List<String> images = (List) textAndImages.get("Images");

            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append(text);

            //使用OCR获取图片中的文本内容
            stringBuffer.append(OCR(images));

            //获得审核结果

            //使用DFA审核文章中是否存在敏感词
            Integer textResult = 1;
            textResult = DFA(stringBuffer.toString());

            //文字上传审核，解决发布文章时，有照片没有文字不能提交的问题

            if(textResult == 1) {
                if (StringUtils.isNotBlank(stringBuffer.toString())) {
                    textResult = baiduTextScan.textScan(stringBuffer.toString());
                }
            }

            Integer imageResult = 1;
            for (String image : images) {
                byte[] imageBytes = fileStorageService.downLoadFile(image);
                imageResult = baiduImageScan.imageScan(imageBytes);
                if(imageResult != 1){
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            //审核通过
            if (textResult == 1 && imageResult == 1) {
                //已到发布时间
                if (wmNews.getPublishTime().before(new Date())) {
                    //调用Feign
                    ArticleDto articleDto = BeanUtil.copyProperties(wmNews, ArticleDto.class);
                    apArticleFeignClient.save(articleDto);
                    wmNews.setStatus((short) 9);
                    wmNewsMapper.update(wmNews, Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId, wmNews.getId()));
                } else {
                    wmNews.setStatus((short) 8);
                    wmNewsMapper.update(wmNews, Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId, wmNews.getId()));

                    Long compare = Duration.between(wmNews.getSubmitedTime().toInstant(), wmNews.getPublishTime().toInstant()).getSeconds();
                    compare = compare * 1000;

                    //int compare = wmNews.getPublishTime().compareTo(new Date());

                    CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());//声明消息的唯一ID，避免ACK冲突

                    Message message = MessageBuilder.withBody(wmNews.getId().toString().getBytes(StandardCharsets.UTF_8))
                            .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                            .setExpiration(compare.toString())
                            .setHeader("x-delay", compare.toString())
                            .build();
                    rabbitTemplate.convertAndSend("delay.exchange", "delay.key", message, correlationData);
                }
            } else if (textResult == 2 || imageResult == 2 || textResult == 4 || imageResult == 4) {
                wmNews.setStatus((short) 2);
                wmNewsMapper.update(wmNews, Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId, wmNews.getId()));
            } else if (textResult == 3 || imageResult == 3) {
                wmNews.setStatus((short) 3);
                wmNewsMapper.update(wmNews, Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId, wmNews.getId()));
            }
        }
    }

    /**
     * 提取文本内容和图片
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> ExtractTextAndImages(WmNews wmNews) {

        StringBuilder stringBuilder = new StringBuilder();
        ArrayList<String> images = new ArrayList<>();

        if (StringUtils.isNotBlank(wmNews.getContent())) {
            List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
            for (Map map : maps) {
                if ("text".equals(map.get("type"))) {
                    stringBuilder.append(map.get("value"));
                }

                if ("image".equals(map.get("type"))) {
                    images.add((String) map.get("value"));
                }
            }
        }

        String imagesStr = wmNews.getImages();
        if (imagesStr != null) {
            String[] split = imagesStr.split(",");
            images.addAll(Arrays.asList(split));
        }
        HashMap<String, Object> textAndImage = new HashMap<>();
        textAndImage.put("Text", stringBuilder.toString());
        textAndImage.put("Images", images);

        return textAndImage;
    }

    /**
     * 构建BufferedImage对象
     * @param urlString
     * @return
     */
    private BufferedImage readImageFromURL(String urlString) {
        try {
            URL url = new URL(urlString);
            BufferedImage image = ImageIO.read(url);
            return image;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 使用OCR提取图片中的文字
     * @return
     */
    private String OCR(List<String> imageUrls){

        StringBuffer stringBuffer = new StringBuffer();

        for (String image : imageUrls) {
            BufferedImage bufferedImage = this.readImageFromURL(image);

            try {
                //提取图片中出现的文字
                String pictureText = tess4jClient.doOCR(bufferedImage);
                stringBuffer.append(pictureText);
            } catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("OCR 提取图片文字失败");
            }
        }

        return stringBuffer.toString();
    }

    /**
     * DFA 本文敏感词审核
     * @param text
     * @return
     */
    private int DFA(String text){

        SensitiveWordFilter sensitiveWordFilter = new SensitiveWordFilter();

        // 查询所有敏感词并存储到ResultList列表中
        //List<WmSensitive> ResultList = wmSensitiveMapper.selectList(null);

        // 初始化一个空的字符串列表，用于存储敏感词
        //List<String> sensitiveList = new ArrayList<>();

        // 遍历ResultList列表，提取每个敏感词并添加到sensitiveList中
        //for (WmSensitive sensitive : ResultList) {
            //sensitiveList.add(sensitive.getSensitives());
        //}

        Set<String> wmSensitive = redisTemplate.opsForSet().members("wm_sensitive");
        List<String> sensitiveList = new ArrayList<>(wmSensitive);

        // 使用sensitiveList中的敏感词构建敏感词过滤器的DFA（Deterministic Finite Automaton）
        sensitiveWordFilter.buildDFA(sensitiveList);

        // 检查给定文本是否包含敏感词
        boolean isSensitiveWord = sensitiveWordFilter.isSensitiveWord(text);

        // 根据是否包含敏感词，返回不同的结果
        if(isSensitiveWord){
            // 如果文本包含敏感词，返回2
            return 2;
        } else {
            // 如果文本不包含敏感词，返回1
            return 1;
        }

    }
}
